/**
 * @PROJECT 
 * @DATE 2017-04-29 16:01:25
 * @AUTHOR LUYU
 */
package com.kool.tlwp.generator;

import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;

import com.kool.tlwp.bean.ColumnVo;
import com.kool.tlwp.bean.ColumnsValue;
import com.kool.tlwp.dao.ColumnsDao;
import com.kool.tlwp.exception.AppException;
import com.kool.tlwp.generator.context.GenerateContext;
import com.kool.tlwp.util.DateUtils;
import com.kool.tlwp.util.PropertyUtils;
import com.kool.tlwp.util.StringUtils;

import freemarker.template.Template;
import freemarker.template.TemplateException;

/**
 * @DESCRIBE
 * @AUTHOR LUYU
 * @DATE 2017-04-29 16:01:25
 *
 */
public class DBCodeGenerator extends CodeGenerator {

	/**
	 * @param tableSchema
	 * @param templateDir
	 * @param destDir
	 * @param pkg
	 * @param isExt
	 * @param tables
	 * @throws AppException
	 */
	public DBCodeGenerator(GenerateContext context) throws AppException {
		super(context);
		if (context == null) {
			throw new AppException("配置信息错误，配置不存在！");
		}

		if (context.getDestDir() == null || context.getDestDir().trim().length() <= 0) {
			throw new AppException("配置信息错误，请设置CODE_DIR");
		}

		if (context.getDriver() == null || context.getDriver().trim().length() <= 0) {
			throw new AppException("配置信息错误，请设置DRIVER");
		}

		if (context.getName() == null || context.getName().trim().length() <= 0) {
			throw new AppException("配置信息错误，请设置USER");
		}

		if (context.getPkg() == null || context.getPkg().trim().length() <= 0) {
			throw new AppException("配置信息错误，请设置PACKAGE");
		}

		if (context.getPwd() == null || context.getPwd().trim().length() <= 0) {
			throw new AppException("配置信息错误，请设置PWD");
		}

		if (context.getTables() == null || context.getTables().trim().length() <= 0) {
			throw new AppException("配置信息错误，请设置TABLES");
		}

		if (context.getTableSchema() == null || context.getTableSchema().trim().length() <= 0) {
			throw new AppException("配置信息错误，请设置TABLE_SCHEMA");
		}

		if (context.getTemplateDir() == null || context.getTemplateDir().trim().length() <= 0) {
			throw new AppException("配置信息错误，请设置TEMPLATE");
		}

		if (context.getUrl() == null || context.getUrl().trim().length() <= 0) {
			throw new AppException("配置信息错误，请设置URL");
		}
	}

	public static void main(String[] args) throws AppException {
		GenerateContext context = new GenerateContext();
		Properties prop = null;
		try {
			prop = PropertyUtils.getSysPropFromRoot();
		} catch (IOException e) {
			throw new AppException("", e);
		}
		context.setPkg(prop.getProperty("PACKAGE"));
		context.setExt(Boolean.valueOf(prop.getProperty("IS_EXTENDS")));
		context.setTables(prop.getProperty("TABLES"));

		context.setTableSchema(prop.getProperty("TABLE_SCHEMA"));
		context.setTemplateDir(prop.getProperty("TEMPLATE"));
		context.setDestDir(prop.getProperty("DIR"));

		context.setUrl(prop.getProperty("URL"));
		context.setDriver(prop.getProperty("DRIVER"));
		context.setName(prop.getProperty("USER"));
		context.setPwd(prop.getProperty("PWD"));
		CodeGenerator genr = new DBCodeGenerator(context);
		genr.generate();
	}

	/**
	 * 
	 * @DESCRIBE 生成Dao.java
	 * @DATE 2017-04-29 16:02:05
	 * @param tableSchema
	 * @param isExt
	 * @throws AppException
	 * @throws IOException
	 * @throws TemplateException
	 *
	 */
	public void generate() throws AppException {

		String[] listTable = context.getTables().split(";");
		String destDir = context.getDestDir() + "\\"
				+ DateUtils.getCurrentTimeString(DateUtils.FORMAT_DATE_AND_TIME_WITHOUT_SPLIT);
		StringUtils.debug("生成文件路径：" + destDir);
		Connection connection = getConnection();
		ColumnsDao dao = new ColumnsDao(connection);
		for (int i = 0; i < listTable.length; i++) {
			String table = listTable[i];
			StringUtils.debug("开始生成 " + table + " 表");

			// 根据表名，读取表结构
			ColumnsValue condition = new ColumnsValue();
			condition.setTableName(table);
			condition.setTableSchema(context.getTableSchema());
			List<ColumnsValue> listRet = null;
			try {
				listRet = dao.select(condition);
			} catch (SQLException e) {
				StringUtils.debug("查询表结构时，数据库异常");
				throw new AppException("查询表结构时，数据库异常");
			}

			try {
				// 获取或创建一个模版。
				Template template = configuration.getTemplate("BaseDao.ftl");
				template.setOutputEncoding("UTF-8");
				// 生成文件到目标文件夹下
				HashMap<String, Object> map = getBaseDaoMap(table, context.getPkg(), listRet);
				Writer writer = getBaseDaoWriter(table, getDaoDir(destDir, context.getPkg()));
				template.process(map, writer);
				writer.flush();
				writer.close();

				template = configuration.getTemplate("Bean.ftl");
				template.setOutputEncoding("UTF-8");
				map = getEntityMap(table, context.getPkg(), listRet);
				writer = getEntityWriter(table, getEntityDir(destDir, context.getPkg()));
				template.process(map, writer);
				writer.flush();
				writer.close();

				template = configuration.getTemplate("BaseXml.ftl");
				template.setOutputEncoding("UTF-8");
				map = getBaseXmlMap(table, context.getPkg(), listRet);
				writer = getBaseXmlWriter(table, getDaoDir(destDir, context.getPkg()));
				template.process(map, writer);
				writer.flush();
				writer.close();

				if (context.isExt()) {
					StringUtils.debug("生成扩展文件...");
					template = configuration.getTemplate("Dao.ftl");
					template.setOutputEncoding("UTF-8");
					map = getDaoMap(table, context.getPkg(), listRet);
					writer = getDaoWriter(table, getDaoDir(destDir, context.getPkg()));
					template.process(map, writer);
					writer.flush();
					writer.close();

					template = configuration.getTemplate("Xml.ftl");
					template.setOutputEncoding("UTF-8");
					map = getXmlMap(table, context.getPkg(), listRet);
					writer = getXmlWriter(table, getDaoDir(destDir, context.getPkg()));
					template.process(map, writer);
					writer.flush();
					writer.close();

				}
				StringUtils.debug("完成");
			} catch (IOException e) {
				throw new AppException("操作Template文件错误!", e);
			} catch (TemplateException e) {
				throw new AppException("操作Template文件错误!", e);
			}
		}
	}

	/**
	 * @DESCRIBE
	 * @DATE 2017-05-01 14:31:04
	 *
	 * @param tabNam
	 * @param destDir
	 * @return
	 * @throws IOException
	 */
	private static Writer getXmlWriter(String tabNam, String destDir) throws IOException {
		String fileName = StringUtils.transferToHumpName(tabNam, true);
		fileName = fileName + "Dao.xml";
		String destPath = destDir + "\\" + fileName;
		Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(destPath), "UTF-8"));
		return writer;
	}

	/**
	 * @DESCRIBE
	 * @DATE 2017-05-01 14:31:02
	 *
	 * @param tabNam
	 * @param pkg
	 * @param listRet
	 * @return
	 */
	private static HashMap<String, Object> getXmlMap(String tabNam, String pkg, List<ColumnsValue> listRet) {
		HashMap<String, Object> map = new HashMap<String, Object>();
		map.put("pkg", pkg);
		map.put("upTumTabNam", StringUtils.transferToHumpName(tabNam, true));
		map.put("lowTumTabNam", StringUtils.transferToHumpName(tabNam, false));
		map.put("tabNam", tabNam);

		ArrayList<ColumnVo> list = new ArrayList<ColumnVo>();
		ArrayList<ColumnVo> pkList = new ArrayList<ColumnVo>();

		boolean hasPk = false;
		for (ColumnsValue value : listRet) {
			value.setDataType(value.getDataType().toUpperCase());
			ColumnVo col = new ColumnVo(value);
			col.setJavaType(ColumnsValue.transferType(value.getDataType()));
			col.setUpJavaName(StringUtils.transferToHumpName(value.getColumnName(), true));
			col.setLowJavaName(StringUtils.transferToHumpName(value.getColumnName(), false));
			list.add(col);

			if ("PRI".equalsIgnoreCase(value.getColumnKey())) {
				hasPk = true;
				pkList.add(col);
			}
		}
		map.put("columns", list);
		map.put("hasPk", hasPk);
		map.put("pkList", pkList);
		return map;
	}

	/**
	 * @DESCRIBE
	 * @DATE 2017-05-01 14:26:02
	 *
	 * @param tabNam
	 * @param destDir
	 * @return
	 * @throws IOException
	 */
	private static Writer getDaoWriter(String tabNam, String destDir) throws IOException {
		String fileName = StringUtils.transferToHumpName(tabNam, true);
		fileName = fileName + "Dao.java";
		String destPath = destDir + "\\" + fileName;
		Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(destPath), "UTF-8"));
		return writer;
	}

	/**
	 * @DESCRIBE
	 * @DATE 2017-05-01 14:26:00
	 *
	 * @param tabNam
	 * @param pkg
	 * @param listRet
	 * @return
	 */
	private static HashMap<String, Object> getDaoMap(String tabNam, String pkg, List<ColumnsValue> listRet) {
		HashMap<String, Object> map = new HashMap<String, Object>();
		map.put("pkg", pkg);
		map.put("upTumTabNam", StringUtils.transferToHumpName(tabNam, true));
		return map;
	}

	/**
	 * @DESCRIBE
	 * @DATE 2017-05-01 08:51:39
	 *
	 * @param tabNam
	 * @param destDir
	 * @return
	 * @throws IOException
	 */
	private static Writer getBaseXmlWriter(String tabNam, String destDir) throws IOException {
		String fileName = StringUtils.transferToHumpName(tabNam, true);
		fileName = "Base" + fileName + "Dao.xml";
		String destPath = destDir + "\\" + fileName;
		Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(destPath), "UTF-8"));
		return writer;
	}

	/**
	 * @DESCRIBE
	 * @DATE 2017-05-01 08:51:36
	 *
	 * @param tabNam
	 * @param pkg
	 * @param listRet
	 * @return
	 */
	private static HashMap<String, Object> getBaseXmlMap(String tabNam, String pkg, List<ColumnsValue> listRet) {
		HashMap<String, Object> map = new HashMap<String, Object>();
		map.put("pkg", pkg);
		map.put("upTumTabNam", StringUtils.transferToHumpName(tabNam, true));
		map.put("lowTumTabNam", StringUtils.transferToHumpName(tabNam, false));
		map.put("tabNam", tabNam);

		ArrayList<ColumnVo> list = new ArrayList<ColumnVo>();
		ArrayList<ColumnVo> pkList = new ArrayList<ColumnVo>();

		boolean hasPk = false;
		for (ColumnsValue value : listRet) {
			value.setDataType(value.getDataType().toUpperCase());
			ColumnVo col = new ColumnVo(value);
			col.setJavaType(ColumnsValue.transferType(value.getDataType()));
			col.setUpJavaName(StringUtils.transferToHumpName(value.getColumnName(), true));
			col.setLowJavaName(StringUtils.transferToHumpName(value.getColumnName(), false));
			col.setIsString(col.getJavaType().equalsIgnoreCase("String"));
			list.add(col);

			if ("PRI".equalsIgnoreCase(value.getColumnKey())) {
				hasPk = true;
				pkList.add(col);
			}
		}
		map.put("columns", list);
		map.put("hasPk", hasPk);
		map.put("pkList", pkList);
		return map;
	}

	/**
	 * @DESCRIBE
	 * @DATE 2017-04-29 17:46:01
	 *
	 * @param tabNam
	 * @param destDir
	 * @return
	 * @throws IOException
	 */
	private static Writer getEntityWriter(String tabNam, String destDir) throws IOException {
		String fileName = StringUtils.transferToHumpName(tabNam, true);
		fileName = fileName + "Bean.java";
		String destPath = destDir + "\\" + fileName;
		Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(destPath), "UTF-8"));
		return writer;
	}

	/**
	 * @DESCRIBE
	 * @DATE 2017-04-29 17:45:05
	 *
	 * @param tabNam
	 * @param pkg
	 * @param listRet
	 * @return
	 */
	private static HashMap<String, Object> getEntityMap(String tabNam, String pkg, List<ColumnsValue> listRet) {
		HashMap<String, Object> map = new HashMap<String, Object>();
		map.put("pkg", pkg);
		map.put("upTumTabNam", StringUtils.transferToHumpName(tabNam, true));
		map.put("lowTumTabNam", StringUtils.transferToHumpName(tabNam, false));
		ArrayList<ColumnVo> list = new ArrayList<ColumnVo>();
		for (ColumnsValue value : listRet) {
			ColumnVo col = new ColumnVo(value);
			col.setJavaType(ColumnsValue.transferType(value.getDataType()));
			col.setUpJavaName(StringUtils.transferToHumpName(value.getColumnName(), true));
			col.setLowJavaName(StringUtils.transferToHumpName(value.getColumnName(), false));
			list.add(col);
		}
		map.put("columns", list);
		return map;
	}

	/**
	 * @DESCRIBE
	 * @DATE 2017-04-29 17:44:05
	 *
	 * @param tabNam
	 * @param destDir
	 * @return
	 * @throws IOException
	 */
	private static Writer getBaseDaoWriter(String tabNam, String destDir) throws IOException {
		String fileName = StringUtils.transferToHumpName(tabNam, true);
		fileName = "Base" + fileName + "Dao.java";
		String destPath = destDir + "\\" + fileName;
		Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(destPath), "UTF-8"));
		return writer;
	}

	/**
	 * @DESCRIBE
	 * @DATE 2017-04-29 17:43:23
	 *
	 * @param tabNam
	 * @param pkg
	 * @return
	 */
	private static HashMap<String, Object> getBaseDaoMap(String tabNam, String pkg, List<ColumnsValue> listRet) {
		HashMap<String, Object> map = new HashMap<String, Object>();
		map.put("pkg", pkg);
		map.put("upTumTabNam", StringUtils.transferToHumpName(tabNam, true));
		map.put("lowTumTabNam", StringUtils.transferToHumpName(tabNam, false));

		boolean hasPk = false;
		for (ColumnsValue value : listRet) {
			if ("PRI".equalsIgnoreCase(value.getColumnKey())) {
				hasPk = true;
				break;
			}
		}
		map.put("hasPk", hasPk);
		return map;
	}
}
